<template>
  <el-select  :placeholder="placeholder" v-model="valueModel"
             clearable @clear="clearChecked" @input="onInput"
             filterable :filter-method="filterMethod">

    <el-option style="display: none" :value="valueModel" :label="label"></el-option>

    <div style="max-height: 200px; min-height: 160px">
      <div class="sea-scroll-bar">
        <el-tree ref="treeRef" node-key="id" :data="tree" default-expand-all accordion @node-click="nodeClick"
                 :filter-node-method="filterNode">
          <template #default="{ node, data }">
            <span class="custom-tree-node">
              <span><i :class="data.icon"></i>{{ data.label }}</span>
            </span>
          </template>
        </el-tree>
      </div>
    </div>
  </el-select>
</template>

<script setup lang="ts">
import {inject, ref, watch} from 'vue';
import Bamboo from "@/lang/bamboo";

import Layers from "@/lang/layers/index";

/**
 * 下拉单选树形选择器
 *
 *
 * element-plus 已经实现了这一功能，但是，直觉上认为应当保留这一代码；
 *
 * 树形组件会包含很复杂的逻辑，这一份代码仍有重要参考价值。
 */
const props = defineProps({
    // 字段名
    name: {type: String}
    // 默认值，注意 value 是单向输入，需要通过 change 事件侦听变化
    , value: {type: [String, Number], default: undefined}
    // 树形数据
    , options: {type: Array, default: Layers.array}
    // 文字提示
    , placeholder: {type: String, default: ''}


    // 可清除
    , clearable: {type: Boolean, default: true}
    // 请求参数，变更会触发查询函数
    , where: {type: Object, default: undefined}
    // 异步获取函数
    , provider: {type: Function, default: undefined}
});

// Emits
const emit = defineEmits(['change']);

/**
 * 组件使用的对象模型
 *
 * @type {FastForm}
 */
const fast_form = inject('fast_form');

/**
 * 组件使用的对象模型
 *
 * @type {FormInput}
 */
const input = fast_form.getFormInput(props.name);
Asserts.notBlank(input, 'form input is undefined:' + props.name);

// 值模型，内部实际在用的绑定数据
const valueModel = ref(props.modelValue || '');
// 显示的文本
const label = ref('');
// 属性数据列表
const tree = ref([]);
// 过滤数值
const filterText = ref('');
// 展示搜索栏
const showSearchbar = ref(false);

// References
const treeRef = ref<InstanceType<typeof ElTree>>()

// Watchers
watch(() => props.value, (val) => {
    if (valueModel.value !== val) {
        valueModel.value = val;
        match();
    }
});

watch(() => props.options, (val) => {
    setOptions(val);
});

/**
 * 侦听 filterText 的变化
 */
watch(filterText, (val) => {
    treeRef.value!.filter(val);
});

/**
 * 过滤数据
 *
 * 当前函数触发之后，会继续触发 filterNode() 函数
 */
const filterMethod = (text) => {
    filterText.value = text;
}

/**
 * 过滤数据
 *
 * filterMethod() 触发之后会自动触发当前函数
 */
const filterNode = (value: string, data: Tree) => {
    if (!value) return true
    return data.label.includes(value)
}


/**
 * 值改变事件
 */
const onInput = (evt) => {
    if (evt instanceof InputEvent) {
        console.log(evt);
    }
}

// Methods
const setOptions = (val) => {
    tree.value = Bamboo.isTree(val) ? val : Bamboo.toTree(val);
    match();
};


/**
 * 数据匹配
 *
 * 重新设置标签值
 */
const match = () => {
    const val = valueModel.value;
    if (Asserts.notBlank(val) || Layers.isEmpty(tree.value)) {
        label.value = '';
    } else {
        const node = Bamboo.getNodeById(tree.value, val);
        label.value = node ? node.getLabel() : val;
    }
};

/**
 * 清除选中
 */
const clearChecked = () => {
    label.value = '';
    valueModel.value = '';
    emit('change', '');
    input.changeValue(val);
};

/**
 * 选中节点
 */
const nodeClick = (node) => {
    label.value = node.label;
    let val = node.id;
    valueModel.value = val;

    emit('change', val);
    input.changeValue(val);
};


// 初始化：设置初始值
setOptions(props.options)

/**
 * 数据受控函数
 *
 * 数据发生变化的时候，会通知到当前组件
 *
 * @see FormInput
 * @param val
 */
const onChangeValue = (val) => {
    valueModel.value = val;
}

// 注册输入组件侦听
input.setDom({onChangeValue})
</script>

<style scoped>
/* Add your styles here */
</style>